#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#define MB ((long) 1024 * 1024)
#define GB (MB * 1024)
#define BUF_SIZ (1 * MB)
#define FILE_SIZ (1 * GB)
#define DEF_FILE_NAME "tmp"

typedef unsigned long uint64;
char buf[BUF_SIZ];

int
main (int argc, char **argv) {
    int fd;
    int need, n;
    unsigned int i, j;
    char name_buf[BUF_SIZ];
    uint64 file_siz;
    uint64 *l_buf;
    char *ptr;
    struct timeval stv, etv;
    strcpy (name_buf, DEF_FILE_NAME);
    file_siz = FILE_SIZ;
    for (i = 1; i < (unsigned int) argc; i++) {
        ptr = argv[i];
        if (*ptr != '-') continue;
        ptr++;
        switch (*ptr)
        {
        case 'f':
            ptr++;
            name_buf[0] = 0;
            strncat (name_buf, ptr, BUF_SIZ-1);
            break;
        case 's':
            ptr++;
            file_siz = atoi (ptr);
            file_siz *= GB;
            if (file_siz <= 0)
                file_siz = FILE_SIZ;
            break;
        default:
            break;
        }
    }
    printf ("NAME:%s\t SIZE:%ldGB\n", name_buf, file_siz/GB);
    printf ("Writing...\n");
    fflush (stdout);
    if ((fd = open (name_buf, O_CREAT | O_TRUNC | O_RDWR,
              S_IRUSR | S_IWUSR)) == -1) {
        perror ("Unable to create file");
        goto error;
    }
    gettimeofday (&stv, NULL);
    for (i = 0; i < file_siz / BUF_SIZ; i++) {
        l_buf = (uint64 *)buf;
        for (j = 0; j < (BUF_SIZ / sizeof(uint64)); j++) {
            l_buf[j] = rand ();
            #define BYTE_BITS 8
            l_buf[j] <<= (BYTE_BITS * 4);
            #undef BYTE_BITS
            l_buf[j] += rand (); 
        }
        need = BUF_SIZ;
        while (need > 0) {
            if ((n = write (fd, l_buf, need)) == -1) {
                perror ("Unable to write");
                goto error;
            }
            need -= n;
        }
    }
    gettimeofday (&etv, NULL);
    double t1, t2;
    t1 = stv.tv_usec;
    t1 /= 1000000;
    t1 += stv.tv_sec;
    t2 = etv.tv_usec;
    t2 /= 1000000;
    t2 += etv.tv_sec;
    printf ("Finished.\n");
    printf ("TIME:%.2lfs\tSPEED:%.2lfMB/s\n", 
                (t2 - t1), ((double)(file_siz)/MB)/(t2 - t1));
    close (fd);
    return EXIT_SUCCESS;
    error:
    return EXIT_FAILURE;

}